package com.blkj.iam.shared.client.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.blkj.iam.common.constant.CommonConstant;
import com.blkj.iam.common.constant.StatusConstants;
import com.blkj.iam.shared.client.service.SsoUserService;
import com.blkj.iam.system.enums.MenuTypeEnum;
import com.blkj.iam.system.model.entity.Menu;
import com.blkj.iam.system.model.entity.User;
import com.blkj.iam.system.model.vo.ShowDeptInfoVO;
import com.blkj.iam.system.model.vo.ShowPermissionVO;
import com.blkj.iam.system.model.vo.ShowUserInfoVO;
import com.blkj.iam.system.service.*;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * @description: 获取用户信息接口
 * @author: Ethan
 * @create: 2025-04-11
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class SsoUserServiceImpl implements SsoUserService {

    private final RedisTemplate<String, Object> redisTemplate;
    private final UserService userService;
    private final DeptService deptService;
    private final MenuService menuService;
    private final UserRoleService userRoleService;
    private final RoleMenuService roleMenuService;


    /***
     * 获取登录用户信息
     * @param loginId
     * @return: cn.hutool.json.JSONObject
     */
    @Override
    public JSONObject getLoginUser(String loginId) {
        JSONObject userObj = new JSONObject();
        ShowUserInfoVO userInfo = userService.getClientUserInfo(loginId);
        userObj.put("userInfo", userInfo);
        return userObj;
    }

    /***
     * 获取登录用户部门信息
     * @param loginId
     * @return: cn.hutool.json.JSONObject
     */
    @Override
    public JSONObject getLoginUserDepart(String loginId) {
        JSONObject deptObj = new JSONObject();
        ShowUserInfoVO userInfo = userService.getClientUserInfo(loginId);
        ShowDeptInfoVO departInfo = deptService.getClientDeptInfo(userInfo.getDepartId());
        deptObj.put("departInfo", departInfo);
        return deptObj;
    }

    /***
     * 获取用户信息
     * @param loginId
     * @return: cn.hutool.json.JSONObject
     */
    @Override
    public JSONObject getUserInfo(String loginId) {
        ShowUserInfoVO userInfo = userService.getClientUserInfo(loginId);
        ShowDeptInfoVO departInfo = deptService.getClientDeptInfo(userInfo.getDepartId());
        JSONObject userObj = new JSONObject();
        userObj.put("userInfo", userInfo);
        userObj.put("departInfo", departInfo);
        return userObj;
    }

    /***
     * 获取权限信息
     * @param
     * @param loginId
     * @return: cn.hutool.json.JSONObject
     */
    @Override
    public JSONObject getPermCode(String loginId) {
        JSONObject userObj = new JSONObject();
        ShowUserInfoVO userInfo = userService.getClientUserInfo(loginId);

        // 1、加载菜单列表
        loadMenuList(userInfo, userObj);

        // 2、加载所有权限列表
        loadAllPermList(userObj);

        // 3、加载当前用户权限列表
        loadPermList(userInfo, userObj);

        // 4、加载当前用户拥有的权限编码
        loadPermCodeList(userInfo, userObj);

        return userObj;
    }

    @Override
    public JSONObject getPermMenu(String loginId) {
        JSONObject userObj = new JSONObject();
        ShowUserInfoVO userInfo = userService.getClientUserInfo(loginId);

        // 1、加载菜单列表
        loadMenuList(userInfo, userObj);

        // 2、加载所有权限列表
        loadAllPermList(userObj);

        // 3、加载当前用户权限列表
        loadPermList(userInfo, userObj);

        return userObj;
    }

    /***
     * 获取用户角色列表
     * @param loginId
     * @return: cn.hutool.json.JSONArray
     */
    @Override
    public JSONArray getUserRole(String loginId) {
        ShowUserInfoVO userInfo = userService.getClientUserInfo(loginId);
        List<String> roleList = userRoleService.getRoleList(userInfo.getId());
        return JSONUtil.parseArray(roleList);
    }

    /***
     * 获取用户权限列表
     * @param loginId
     * @return: cn.hutool.json.JSONArray
     */
    @Override
    public JSONArray getUserPermList(String loginId) {
        ShowUserInfoVO userInfo = userService.getClientUserInfo(loginId);
        List<String> permList = roleMenuService.getPermList(userInfo.getId());
        return JSONUtil.parseArray(permList);
    }

    /***
     * 分页查询用户列表 当前用户所属部门下所有用户数据
     * @param params
     * @return: com.blkj.iam.shared.client.dto.PageVo
     */
    @Override
    public Page<User> getUserList(Map<String, Object> params) {
        int pageNo = Integer.parseInt(params.get("pageNo").toString());
        int pageSize = Integer.parseInt(params.get("pageSize").toString());
        String userType = params.get("userType").toString();
        String loginId = params.get("loginId").toString();
        String username = params.getOrDefault("username", "").toString();
        String realName = params.getOrDefault("realname", "").toString();

        // 获取用户信息
        ShowUserInfoVO userInfo = userService.getClientUserInfo(loginId);
        if (userInfo.getIsAdmin()){
            Page<User> userPage = userService.page(new Page<>(pageNo, pageSize), new LambdaQueryWrapper<User>()
                    .eq(User::getTenantId, userInfo.getLoginTenantId())
                    .eq(User::getUserType, userType)
                    .eq(ObjectUtil.isNotEmpty(username), User::getUsername, username)
                    .like(ObjectUtil.isNotEmpty(realName), User::getNickname, realName));

            userPage.setRecords(
                    userPage.getRecords().stream().map(user -> {
                        // 获取部门名称并设置到 user 对象中
                        user.setDeptName(deptService.getById(user.getDeptId()).getName());
                        return user;
                    }).collect(Collectors.toList())
            );

            return userPage;
        }

        return new Page<>();
    }

    /**
     * 加载当前用户拥有的权限编码
     *
     * @param sysUser
     * @param userObj
     * @return: void
     */
    private void loadPermCodeList(ShowUserInfoVO sysUser, JSONObject userObj) {
        Object permCodeListJson = redisTemplate.opsForValue().get(CommonConstant.PERM_CODE_LIST);

        // 如果缓存中不存在或者缓存中的权限列表为空
        if (permCodeListJson == null || permCodeListJson.equals("[]")) {
            JSONArray authList = userObj.getJSONArray("tempAuthList");
            List<String> actionList = new ArrayList<>();

            if (ObjectUtil.isNotEmpty(authList)) {
                // 从 authList 中提取 action 属性
                actionList = authList.stream().map(item -> ((JSONObject) item).getStr("action")).filter(action -> action != null).collect(Collectors.toList());
            }

            // 将结果存入 userObj 和缓存
            userObj.put("codeList", actionList);
            redisTemplate.opsForValue().set(CommonConstant.PERM_CODE_LIST, JSONUtil.toJsonStr(actionList));
        } else {
            // 如果缓存中存在且不为空，直接使用缓存中的数据
            userObj.put("codeList", JSONUtil.parseArray(permCodeListJson));
        }

        // 删除 tempAuthList
        userObj.remove("tempAuthList");
        userObj.remove("menu");
    }

    /**
     * 加载当前用户权限列表
     *
     * @param sysUser
     * @param userObj
     * @return: void
     */
    private void loadPermList(ShowUserInfoVO sysUser, JSONObject userObj) {
        Object permListJson = redisTemplate.opsForValue().get(CommonConstant.PERM_LIST);
        if (permListJson == null || permListJson.equals("[]")) {
            // 如果缓存中不存在或者缓存中的菜单列表为空，从数据库中查询
            List<Menu> userPermList = menuService.getMenuList(sysUser.getId(), sysUser.getLoginTenantId());

            // 使用 Stream 过滤和处理数据
            JSONArray jsonArray = new JSONArray();
            userPermList.stream().filter(menu -> MenuTypeEnum.BUTTON.getValue().equals(menu.getType())).forEach(menu -> {
                JSONObject json = new JSONObject();
                json.put("action", menu.getPerm());
                json.put("describe", menu.getName());
                json.put("type", menu.getPermType());
                jsonArray.add(json);
            });

            userObj.put("auth", jsonArray);
            userObj.put("tempAuthList", jsonArray);
            userObj.set("sysSafeMode", true);

            // 将查询结果存入缓存
            redisTemplate.opsForValue().set(CommonConstant.PERM_LIST, JSONUtil.toJsonStr(jsonArray));
        } else {
            // 如果缓存中存在且不为空，直接使用缓存中的数据
            userObj.put("auth", JSONUtil.parseArray(permListJson));
            userObj.set("sysSafeMode", true);
        }
    }

    /**
     * 加载所有权限列表
     *
     * @param userObj
     * @return: void
     */
    private void loadAllPermList(JSONObject userObj) {
        Object allPermListJson = redisTemplate.opsForValue().get(CommonConstant.ALL_PERM_LIST);
        if (allPermListJson == null || allPermListJson.equals("[]")) {
            // 如果缓存中不存在或者缓存中的菜单列表为空，从数据库中查询
            JSONArray menuList = userObj.getJSONArray("tempMenuList");

            // 将 JSONArray 转换为 List<Menu>
            List<Menu> allMenuList = JSONUtil.toList(menuList, Menu.class);

            // 使用 Stream 过滤和处理数据
            JSONArray jsonArray = new JSONArray();
            allMenuList.stream().filter(menu -> MenuTypeEnum.BUTTON.getValue().equals(menu.getType())).forEach(menu -> {
                JSONObject json = new JSONObject();
                json.put("action", menu.getPerm());
                json.put("describe", menu.getName());
                json.put("status", menu.getStatus().toString());
                json.put("type", menu.getPermType().toString());
                jsonArray.add(json);
            });

            userObj.put("allAuth", jsonArray);
            userObj.remove("tempMenuList");

            // 将查询结果存入缓存
            redisTemplate.opsForValue().set(CommonConstant.ALL_PERM_LIST, jsonArray);
        } else {
            // 如果缓存中存在且不为空，直接使用缓存中的数据
            userObj.put("allAuth", JSONUtil.parseArray(allPermListJson));
        }
    }

    /**
     * 加载菜单列表
     *
     * @param sysUser
     * @param userObj
     * @return: void
     */
    private void loadMenuList(ShowUserInfoVO sysUser, JSONObject userObj) {
        Object menuListJson = redisTemplate.opsForValue().get(CommonConstant.MENU_LIST);

        // 如果缓存中不存在或者缓存中的菜单列表为空
        if (menuListJson == null || menuListJson.equals("[]")) {
            // 从数据库中查询菜单列表
            List<Menu> allMenuList = loadMenuListFromDatabase(sysUser);

            // 构建菜单结构
            List<ShowPermissionVO> rootMenus = getPermissions(allMenuList);

            // 将查询结果存入缓存，设置30分钟过期
            redisTemplate.opsForValue().set(CommonConstant.MENU_LIST, JSONUtil.toJsonStr(rootMenus), 30, TimeUnit.MINUTES);

            // 将结果放入 userObj
            userObj.put("menu", JSONUtil.parseArray(JSONUtil.toJsonStr(rootMenus)));
            userObj.put("tempMenuList", allMenuList);
        } else {
            // 如果缓存中存在且不为空，直接使用缓存中的数据
            userObj.put("menu", JSONUtil.parseArray(menuListJson));
        }
    }

    private List<Menu> loadMenuListFromDatabase(ShowUserInfoVO sysUser) {
        Boolean isAdmin = sysUser.getIsAdmin();
        if (isAdmin) {
            // 超级管理员
            return menuService.getAllMenuList(sysUser.getLoginTenantId());
        } else {
            // 普通用户
            return menuService.getMenuList(sysUser.getId(), sysUser.getLoginTenantId());
        }
    }

    /**
     * 封装菜单列表
     *
     * @param allMenuList
     * @return: java.util.List<com.blkj.iam.auth.permission.vo.ShowPermission>
     */
    @NotNull
    private static List<ShowPermissionVO> getPermissions(List<Menu> allMenuList) {
        List<Menu> sortedList = allMenuList.stream().filter(menu -> !menu.getType().equals(MenuTypeEnum.BUTTON.getValue()) && menu.getVisible().equals(StatusConstants.ENABLE)).sorted(Comparator.comparing(Menu::getSort)).toList();

        // 将所有菜单项存入 Map，方便通过 ID 快速查找
        Map<Long, ShowPermissionVO> menuMap = sortedList.stream().map(Menu::toShowPermission).collect(Collectors.toMap(ShowPermissionVO::getId, menu -> menu));

        // 构建父子菜单结构
        List<ShowPermissionVO> rootMenus = new ArrayList<>();
        for (Menu permission : sortedList) {
            ShowPermissionVO showPermission = menuMap.get(permission.getId());
            if (permission.getParentId() == 0) {
                // 顶级菜单
                rootMenus.add(showPermission);
            } else {
                // 子菜单
                ShowPermissionVO parentMenu = menuMap.get(permission.getParentId());
                if (ObjectUtil.isNotEmpty(parentMenu)) {
                    if (ObjectUtil.isEmpty(parentMenu.getChildren())) {
                        parentMenu.setChildren(new ArrayList<>());
                    }
                    parentMenu.getChildren().add(showPermission);
                    parentMenu.getChildren().sort(Comparator.comparing(ShowPermissionVO::getSort));
                }
            }
        }

        return rootMenus;
    }
}